package com.yj.auto.plugin.generator;

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.util.List;
import java.util.Map;

import javax.sql.DataSource;

import com.jfinal.kit.Kv;
import com.jfinal.kit.Prop;
import com.jfinal.kit.PropKit;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.dialect.Dialect;
import com.jfinal.plugin.activerecord.dialect.MysqlDialect;
import com.jfinal.plugin.activerecord.generator.TableMeta;
import com.jfinal.plugin.druid.DruidPlugin;
import com.jfinal.template.Engine;
import com.jfinal.template.Template;
import com.xiaoleilu.hutool.io.FileUtil;
import com.yj.auto.Constants;

public class AutoGenerator {
	DataSource dataSource = null;
	protected Dialect dialect = null;
	protected AutoMetaBuilder metaBuilder;
	private String templatePath = null;
	private String targetPath = null;
	private String tableRemovePrefixes = null;
	private String viewPath = null;
	private String basepackage = null;
	private String[] tables = null;

	public AutoGenerator(String tableRemovePrefixes, String viewPath, String basepackage) {
		this(tableRemovePrefixes, viewPath, basepackage, getDataSourceByConfig());
	}

	public AutoGenerator(String tableRemovePrefixes, String viewPath, String basepackage, DataSource dataSource) {
		this.init(tableRemovePrefixes, viewPath, basepackage);
		this.dataSource = dataSource;
		dialect = new MysqlDialect();
		metaBuilder = new AutoMetaBuilder(dataSource);
		metaBuilder.setRemovedTableNamePrefixes(tableRemovePrefixes);
	}

	private void init(String tableRemovePrefixes, String viewPath, String basepackage) {
		templatePath = Constants.CONFIG("GENERATOR_TEMPLATE");
		targetPath = Constants.SYS_TEMP_FILE_ROOT + "output" + File.separator + System.currentTimeMillis() + File.separator;
		this.tableRemovePrefixes = tableRemovePrefixes;
		this.viewPath = viewPath;
		this.basepackage = basepackage;
	}

	public void generate(String... tables) throws Exception {
		if (StrKit.isBlank(getTargetPath())) {
			System.err.println("目标目录" + this.getTargetPath() + "不能为空!");
			return;
		}
		List<File> files = listTemplateFile();
		if (null == files || files.size() < 1) {
			System.err.println("模板文件" + this.getTemplatePath() + "不能为空!");
			return;
		}
		FileUtil.del(getTargetPath());// 删除文件生成目录
		List<TableMeta> tableMetas = metaBuilder.build(tables);
		String packagePath = getBasepackagePath();
		Engine gin = Engine.use().setBaseTemplatePath(this.getTemplatePath());
		gin.setEncoding(Constants.SYS_ENCODING);
		try {
			gin.addSharedStaticMethod(StrKit.class);
		} catch (Exception e) {

		}
		for (TableMeta tm : tableMetas) {
			Kv kv = new Kv();
			kv.set("basepackage", this.getBasepackage());
			kv.set("packagePath", packagePath);
			kv.set("viewPath", viewPath);
			kv.set("sqlnamespace", viewPath.replaceAll("/", "."));
			kv.set("table", tm);
			kv.set("simpleName", tm.name.toLowerCase().replace(tableRemovePrefixes, ""));
			kv.set("modelName", tm.modelName);
			for (File file : files) {
				this.render(gin, kv, file);
			}
			System.out.println("table:" + tm.name + " success");
		}
	}

	protected void render(Engine gin, Kv kv, File templateFile) throws Exception {
		OutputStreamWriter out = null;
		try {
			int pathIdx = this.getTemplatePath().length();
			String templateFilePath = templateFile.getAbsolutePath().substring(pathIdx);
			// System.out.println(templateFilePath);
			String targetPath = getTargetPath(templateFilePath, kv);
			// System.out.println(targetPath);
			File targetFile = new File(getTargetPath() + targetPath);
			if (templateFile.isDirectory()) {
				if (!targetFile.exists())
					FileUtil.mkdir(targetPath);
			} else {
				Template template = gin.getTemplate(templateFilePath);
				FileUtil.mkParentDirs(targetFile);
				out = new OutputStreamWriter(new FileOutputStream(targetFile), Constants.SYS_ENCODING);
				template.render(kv, out);
			}
		} finally {
			if (null != out) {
				out.flush();
				out.close();
			}
		}
	}

	protected String getTargetPath(String templateFilePath, Map dataMap) {
		Engine gin = Engine.use();
		Template template = gin.getTemplateByString(templateFilePath);
		String path = template.renderToString(dataMap);
		return path;
	}

	protected List<File> listTemplateFile() {
		if (StrKit.isBlank(getTemplatePath())) {
			return null;
		}
		File templateDir = new File(this.getTemplatePath());
		if (!templateDir.exists()) {
			return null;
		}
		List<File> files = FileUtil.loopFiles(templateDir);
		return files;
	}

	public DataSource getDataSource() {
		return dataSource;
	}

	public void setDataSource(DataSource dataSource) {
		this.dataSource = dataSource;
	}

	public String[] getTables() {
		return tables;
	}

	public void setTables(String[] tables) {
		this.tables = tables;
	}

	public Dialect getDialect() {
		return dialect;
	}

	public void setDialect(Dialect dialect) {
		this.dialect = dialect;
	}

	public AutoMetaBuilder getMetaBuilder() {
		return metaBuilder;
	}

	public void setMetaBuilder(AutoMetaBuilder metaBuilder) {
		this.metaBuilder = metaBuilder;
	}

	public String getTemplatePath() {
		return templatePath;
	}

	public void setTemplatePath(String templatePath) {
		this.templatePath = templatePath;
	}

	public String getTargetPath() {
		return targetPath;
	}

	public void setTargetPath(String targetPath) {
		this.targetPath = targetPath;
	}

	public String getTableRemovePrefixes() {
		return tableRemovePrefixes;
	}

	public void setTableRemovePrefixes(String tableRemovePrefixes) {
		this.tableRemovePrefixes = tableRemovePrefixes;
	}

	public String getSubsystem() {
		return viewPath;
	}

	public void setSubsystem(String subsystem) {
		this.viewPath = subsystem;
	}

	public String getBasepackage() {
		if (!StrKit.isBlank(viewPath)) {// 基本包名+子系统
			return basepackage + "." + viewPath.replaceAll("/", ".");
		}
		return basepackage;
	}

	public String getBasepackagePath() {
		String packagePath = this.getBasepackage().replaceAll("\\.", "\\\\");
		return packagePath;
	}

	public void setBasepackage(String basepackage) {
		this.basepackage = basepackage;
	}

	private static DataSource getDataSourceByConfig() {
		Prop p = PropKit.use("conf/jdbc.properties");
		DruidPlugin druidPlugin = new DruidPlugin(p.get("jdbc.url"), p.get("jdbc.user"), p.get("jdbc.password"));
		String connProps = "remarks=true;useInformationSchema=true";// 获取备注
		druidPlugin.setConnectionProperties(connProps);
		druidPlugin.start();
		return druidPlugin.getDataSource();
	}

}
